package com.xlx.openLink.service;

import com.alibaba.druid.stat.TableStat;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xlx.openLink.base.BasePage;
import com.xlx.openLink.base.BaseUtils;
import com.xlx.openLink.base.SnmpException;
import com.xlx.openLink.base.ThreadRunTimeExcption;
import com.xlx.openLink.conf.ApplicationContextUtils;
import com.xlx.openLink.dao.AlarmMapper;
import com.xlx.openLink.dao.ConditionsMapper;
import com.xlx.openLink.dao.DeviceMapper;
import com.xlx.openLink.dao.PortMapper;
import com.xlx.openLink.entity.baseenity.MibSystem;
import com.xlx.openLink.entity.device.DeviceInfo;
import com.xlx.openLink.entity.pojo.Conditions;
import com.xlx.openLink.entity.pojo.Device;
import com.xlx.openLink.entity.pojo.Port;
import com.xlx.openLink.entity.snmpenity.MibIfEntry;
import com.xlx.openLink.enums.DevStatusEnum;
import com.xlx.openLink.enums.DevTypeEnum;
import com.xlx.openLink.enums.ResultCodeEnum;
import com.xlx.openLink.snmp.base.SNMPTarget;
import com.xlx.openLink.snmp.imp.SNMPAPIImpl;
import com.xlx.openLink.snmp.utils.SNMPUtils;
import com.xlx.openLink.template.OpenLinkTemplate;
import com.xlx.openLink.uitls.AssertUtils;
import com.xlx.openLink.uitls.Commuitls;
import com.xlx.openLink.vo.RequestDevtLst;
import com.xlx.openLink.vo.RequestPortLst;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.*;

@Slf4j
@Service
public class DeviceService {

    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private SNMPAPIImpl snmpApi;
    @Autowired
    private PortMapper portMapper;
    @Autowired
    private AlarmMapper alarmMapper;
    @Autowired
    private ConditionsMapper conditionsMapper;

    @Autowired
    private OpenLinkTemplate openLinkTemplate;


    /**
     * 添加设备 之后调用初始化设备的方式
     *
     * @param device
     */
    @Transactional
    public Device add(Device device) {
        //参数校验
        AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_BLANK), device);
        AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_BLANK), device.getDevName());
        AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_BLANK), device.getDevIp());
        AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_BLANK), device.getDevType());
        if (!DevTypeEnum.CameraType.getCode().equalsIgnoreCase(device.getDevType())) {
            AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_BLANK), device.getDevSnmpPort());
            AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_BLANK), device.getDevReadcommunity()); //读
        }
        AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_BLANK, "设备类错误"), DevTypeEnum.getByCode(device.getDevType()));
        //产看设备
        Device ret = deviceMapper.selectByIp(device.getDevIp());
        if (ret != null) {
            throw new ThreadRunTimeExcption(ResultCodeEnum.DATA_NOT_EXIST, "设备已经存在");
        } else {
            if (Commuitls.ping(device.getDevIp())) {
                log.info(device.getDevName() + "设备在线");
                device.setDevStatus(DevStatusEnum.ONLINE.getCode());
            } else {
                log.info(device.getDevName() + "设备不在线");
                device.setDevStatus(DevStatusEnum.OFFLINE.getCode());
            }
        }
        device.setDevCreateDate(new Date());
        device.setDevUpdateDate(new Date());
        device.setPkGuid(BaseUtils.createGUID());
        deviceMapper.insertSelective(device);
        return device;
    }

    /**
     * 初始化设备
     *
     * @param pkGuid
     */

    @Transactional
    public void initDev(String pkGuid) {
        List<Port> ports = new ArrayList<>();
        MibSystem mibSystem = null;
        AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_BLANK), pkGuid);
        Device device = deviceMapper.selectByPrimaryKey(pkGuid);
        //初始化设备
        AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.DATA_NOT_EXIST, "设备不存在"), device);
        if (Commuitls.ping(device.getDevIp())) {
            device.setDevStatus(DevStatusEnum.ONLINE.getCode());
            log.info("设备在线");
            device.setDevUpdateDate(new Date());
            //正常情况
            if (!device.getDevType().equalsIgnoreCase(DevTypeEnum.CameraType.getCode())) {//不是摄像头设备
                try {
                    mibSystem = this.getSysInfo(device); //获取设备信息
                    if (mibSystem != null) {
                        device.setDevDescor(mibSystem.getSysDescr());
                        device.setDevOid(mibSystem.getMappingOID());
                        device.setDevSysUpTime(String.valueOf(mibSystem.getSysUpTime()));
                        device.setDevSysName(mibSystem.getSysName());//获取系统名称
                        device.setDevUpdateDate(new Date());
                        this.getMainMAC(device);
                    }
                } catch (SnmpException e) {
                    log.error("错误" + e.getMessage());
                    log.error("获取端口错误");
                }
                // 2 获取设备需要的参数
                if (!device.getDevType().equalsIgnoreCase(DevTypeEnum.ComputerType.getCode())) {
                    initIfTable(device, ports);
                }
            }
        } else {
            device.setDevStatus(DevStatusEnum.OFFLINE.getCode());
            device.setDevUpdateDate(new Date());
            log.info("设备不在线");
        }
        deviceMapper.updateByPrimaryKey(device);
        List<Port> inList = new ArrayList<>();
        List<Port> upList = new ArrayList<>();
        List<Port> rePort = portMapper.selectByDevId(device.getPkGuid());
        for (Port p : ports) {
            boolean flag = false;
            for (Port rp : rePort) {
                if (p.equals(rp)) {
                    this.initData(rp, p);
                    upList.add(rp);
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                inList.add(p);
            }
        }
        if (inList.size() >= 1) {
            portMapper.insertBatch(inList);//批量插入
        }
        if (upList.size() >= 1) {
            portMapper.updateBatch(upList);
        }
    }

    /**
     * 初始化数据
     *
     * @param rp
     * @param p
     */
    public void initData(Port rp, Port p) {
        rp.setpStatus(p.getpStatus());
        rp.setpName(p.getpName());
        rp.setpInoctets(p.getpInoctets());
        rp.setpOutoctets(p.getpOutoctets());
        rp.setpUpdateDate(new Date());
    }


    /**
     * 初始化ifTable
     *
     * @param device
     * @param ports
     */
    public void initIfTable(Device device, List<Port> ports) {
        List<MibIfEntry> list = Collections.EMPTY_LIST;
        list = this.getMibIfEntry(device);
        list.forEach(e -> {
            //if (e.getIfType() == 6 || e.getIfType() == 117 || e.getIfType() == 64 || e.getIfType() == 71) {
                Port port = new Port();
                port.setPkId(BaseUtils.createGUID());
                port.setpDevIp(device.getDevIp());
                port.setpInOid(e.getMappingOID() + "." + 10 + "." + e.getIfIndex());
                port.setpOutOid(e.getMappingOID() + "." + 16 + "." + e.getIfIndex());
                port.setpIndex(e.getIfIndex());
                port.setpDescr(e.getIfDescr());
                port.setpCreateDate(new Date());
                port.setpUpdateDate(new Date());
                port.setpDevId(device.getPkGuid());
                port.setpSpeed(Double.valueOf(e.getIfSpeed()) / (8 * 1024 * 1024)); //固定速度
                port.setpStatus(String.valueOf(e.getIfOperStatus()));
                port.setpDevName(device.getDevName());
                port.setpInoctets(e.getIfInOctets());
                port.setpOutoctets(e.getIfOutOctets());
                ports.add(port);
            //}
        });
    }


    /**
     * @param device
     * @return
     * @throws SnmpException
     */
    public MibSystem getSysInfo(Device device) throws SnmpException {
        MibSystem mibSystem = new MibSystem();
        MibSystem mibObject = null;
        SNMPTarget snmpTarget = new SNMPTarget();
        snmpTarget.setPort(device.getDevSnmpPort());
        snmpTarget.setReadCommunity(device.getDevReadcommunity());
        snmpTarget.setSnmpVersion(device.getDevSnmpVersion());
        snmpTarget.setNodeIP(device.getDevIp());
        try {
            mibObject = (MibSystem) snmpApi.getMibObject(mibSystem, snmpTarget);
        } catch (SnmpException | IOException e) {
            log.info(e.getMessage());
            throw new SnmpException(e.getMessage());
        }
        return mibObject;
    }

    public void getMainMAC(Device device) {
        try {
            SNMPTarget snmpTarget = new SNMPTarget();
            snmpTarget.setPort(device.getDevSnmpPort());
            snmpTarget.setReadCommunity(device.getDevReadcommunity());
            snmpTarget.setSnmpVersion(device.getDevSnmpVersion());
            snmpTarget.setNodeIP(device.getDevIp());
            String value = snmpApi.getOIDValue("1.3.6.1.2.1.17.1.1.0", snmpTarget);
            value = SNMPUtils.formatDispayMacAddress(value);
            device.setDevMac(value);
        } catch (Exception e) {
            log.error("获取" + device.getDevIp() + "主MAC信息出错:" + e.getMessage());
        }

    }

    public List<MibIfEntry> getMibIfEntry(Device device) {
        List<MibIfEntry> ifEntryList = Collections.EMPTY_LIST;
        SNMPTarget snmpTarget = new SNMPTarget();
        snmpTarget.setPort(device.getDevSnmpPort());
        snmpTarget.setReadCommunity(device.getDevReadcommunity());
        snmpTarget.setSnmpVersion(1);
        snmpTarget.setNodeIP(device.getDevIp());
        try {
            ifEntryList = snmpApi.getAllTableData(MibIfEntry.class, snmpTarget);
        } catch (Exception e) {
            log.info("执行错误");
            log.error(e.toString());
        }
        return ifEntryList;
    }

    public List<MibIfEntry> getMibIfEntry(String ip, int port, int version, String community) {
        List<MibIfEntry> ifEntryList = Collections.EMPTY_LIST;
        SNMPTarget snmpTarget = new SNMPTarget();
        snmpTarget.setPort(port);
        snmpTarget.setReadCommunity(community);
        snmpTarget.setSnmpVersion(version);
        snmpTarget.setNodeIP(ip);
        try {
            ifEntryList = snmpApi.getAllTableData(MibIfEntry.class, snmpTarget);
        } catch (Exception e) {
            log.info(e.getMessage());
        }
        return ifEntryList;
    }

    /**
     * uppdate dev
     *
     * @param device
     * @return
     */
    @Transactional
    public void update(Device device) {
        List<Device> list = deviceMapper.selectByIpList(device.getDevIp());
        if (list.size() == 1 && list.get(0).getPkGuid().equals(device.getPkGuid())) {
            device.setDevUpdateDate(new Date());
            deviceMapper.updateByPrimaryKeySelective(device);
        } else if (CollectionUtils.isEmpty(list)) {
            deviceMapper.updateByPrimaryKeySelective(device);
            portMapper.deleteByDevId(device.getPkGuid());
        } else {
            throw new ThreadRunTimeExcption(ResultCodeEnum.DATA_DUPLICATE, "IP地址已经存在");
        }

    }

    /**
     * 删除设备
     *
     * @param
     * @return
     */
    @Transactional()
    public int delDev(String pkGuid) {

        portMapper.deleteByDevId(pkGuid); //删除端口信息
        Conditions c = conditionsMapper.selectByDevId(pkGuid);
        if (c != null) {
            conditionsMapper.deleteByPrimaryKey(c.getPkGuid());
        }
        return deviceMapper.deleteByPrimaryKey(pkGuid);
    }

    public Device select(String pkGuid) {
        return deviceMapper.selectByPrimaryKey(pkGuid);
    }

    /**
     * 批量删除设备
     *
     * @param pkGuids
     * @return
     */
    public void delDevList(List<String> pkGuids) {
        for (String str : pkGuids) {
            deviceMapper.deleteByPrimaryKey(str);
        }
    }

    /**
     * 批量更新操作
     *
     * @param list
     * @return
     */
    public int updateBatch(List<Device> list) {
        int loopCount = list.size() / 100;
        int left = list.size() % 100;
        for (int i = 0; i < loopCount; i++) {
            int fromIndex = i * 100;
            deviceMapper.updateBatch(list.subList(fromIndex, fromIndex + 100));
        }
        if (left > 0) {
            int fromIndex = loopCount * 100;
            deviceMapper.updateBatch(list.subList(fromIndex, fromIndex + left));
        }
        return 1;
    }

    /**
     * 分页查询
     *
     * @param request
     * @return
     */
    public BasePage<Device> listByPage(RequestDevtLst request) {
        AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_BLANK), request);
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<Device> list = deviceMapper.listByPage(request);
        PageInfo pageInfo = new PageInfo(list);
        return new BasePage<Device>(pageInfo.getList(), pageInfo.getPageNum(), pageInfo.getPageSize(), pageInfo.getTotal());
    }


    public HashMap initData() {
        HashMap retMap = new HashMap();
        retMap.put("allSwitch", deviceMapper.allSwitch());
        retMap.put("onLine", deviceMapper.onLine());
        retMap.put("allCamera", deviceMapper.allCamera());
        retMap.put("allDev", deviceMapper.allDev());
        retMap.put("allAlarm", alarmMapper.allAlarm());
        retMap.put("dealAlarm", alarmMapper.dealAlarm());
        retMap.put("me", BaseUtils.getMemery());
        retMap.put("cup", BaseUtils.getCpuLoad());
        return retMap;
    }


}
